//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "config.h"
#include "command.h"
#include "flash.h"
#include "serial.h"
#include "time.h"
#include "main.h"
#include "util.h"
#include "bulverde.h"
#include "net.h"
#include "smc91x.h"
#include "irq.h"
#include "xmodem.h"
#include "ymodem.h"
#include "mem.h"
#include "tat.h"
#include "crc16.h"
#include "usb_serial_download.h"
#include "pxa_usb.h"
#include "doc_op.h"
#include "pcf50606.h"
#include "bcm2121.h"
#include "KeypadTest.h"

#define TAT 1

//The following is used to update the whole Image by USB

volatile int iimageupdate_by_usb=0;
#ifdef TAT
unsigned int verbose_level = 1;
#endif

extern int udownload_cmd(u32 *destAddress, u32 bufLen);
extern int UsbDownloadImageEx();
extern int _UsbDownloadImageEx(unsigned long);
extern int md5_stream (char *start_address, int length);
void BootKernel(int arg0, int arg1);
void BootLinux();
void Download(u8* address);
void Jump(u32* address);
void JumptoTAT(void);
void PrintHelp(void);
void ShowVersion(void);
int ReadBoot(int addr, int len);
int WriteBoot(int addr, int len);

void ResetTerminal(void);
void PrintSerialSpeed(eBauds speed);
void ExecuteCommand(u8* commandline);
void hw_reset(void);
int SplitRam(int addr, int nSize);
void ArmSys();
void tat_menu();

int g_bWrite = 1;

#ifdef TAT
unsigned char rts_signal;
int rts_try;
#endif

#define CCCR_ADDR   0x41300000

void ChangeFreq(int l, int twoN, int turbo, int b)
{
    int value;
    volatile int *regT;

    regT = (volatile int *)CCCR_ADDR;
    value = *regT;
    value &= 0x3FFFFFFF;                //make sure the Core and Peripheral PLL disable bits are clear.
    value = value & 0xFFFFF000;         //clear the L and 2N bits

    l = l & 0x1F;                   //make sure L is only 0 thru 31
    value |= l;                     //OR in the L value

    twoN = twoN & 0xf;              //make sure 2N is only 0 thru 15
    value |= (twoN << 7);               //OR in the 2N value

    if (l == 7) //91MHz
        value &= ~(1<<25);
    else
        value |= (1<<25);           //Alternate Setting for Memory Controller Clock

    *regT = value;                  //now set the CCCR register

    if (turbo == 0 && b == 0) {
        __asm("mov  r0, #0x2");                 //set to Frequency Change Mode
        __asm("mcr  p14, 0, r0, c6, c0, 0");    //write to the CLKCFG coprocessor reg
    }

    if (turbo != 0 && b == 0) {
        __asm("mov  r0, #0x3");                 //set to Frequency Change Mode
        __asm("mcr  p14, 0, r0, c6, c0, 0");    //write to the CLKCFG coprocessor reg
    }

    if (turbo != 0 && b != 0) {
        __asm("mov  r0, #0xB");                 //set to Frequency Change Mode
        __asm("mcr  p14, 0, r0, c6, c0, 0");    //write to the CLKCFG coprocessor reg
    }
}

void ShowUsbPinState(void)
{
    printk("GPIO40 (B_USB_FULLSPEED) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000100) ? 1 : 0, (GPLR1 & 0x00000100) ? 1 : 0, (GAFR1_L & 0x00030000) >> 16 );
    printk("GPIO38 (B_OTG_PWREN    ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000040) ? 1 : 0, (GPLR1 & 0x00000040) ? 1 : 0, (GAFR1_L & 0x00003000) >> 12);
    printk("GPIO35 (B_USB_DEC_N    ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000008) ? 1 : 0, (GPLR1 & 0x00000008) ? 1 : 0, (GAFR1_L & 0x000000C0) >> 6);
    printk("GPIO41 (B_OTG_ID       ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR1 & 0x00000200) ? 1 : 0, (GPLR1 & 0x00000200) ? 1 : 0, (GAFR1_L & 0x000C0000) >> 18);
    printk("GPIO22 (B_OTG_PWRFLG   ) : Dir(%d), Level(%d), Alt(%d) \n", (GPDR0 & 0x00400000) ? 1 : 0, (GPLR0 & 0x00400000) ? 1 : 0, (GAFR0_U & 0x00003000) >> 12);
}

void Xs_LCD_Init();
void Display_Logo();
void PCFWatchDogEnable(int IsEnable);
int onkeyPressed = 0;
char getOOCS();
char getOOCC1();
void setOOCC2();
char getINT1();
void pcf50606_power_off(void);
void backlight_open();

void check_onkey()
{
    if (onkeyPressed) {
        char oocs = getOOCS();
        if (jiffies < 100 && (oocs&0x01) && !(oocs&0x20)) {
            //printk("should off dump %x,%x,%x\n",jiffies,oocs,getOOCC1());
            pcf50606_power_off();
        }
        else if (jiffies >= 100) {//2-3s ~ 100 jiffies
            //printk("normal dump %x,%x,%x\n",jiffies,oocs,getOOCC1());
            backlight_open();
            onkeyPressed = 0;//reset
        }
    }
}

void c_main(void)
{
    int i;
    unsigned char commandline[128] = {0,};
    int retval = 0;
    int bAutoload = 1;

    /*change frequence to 312/208/104 turbo mode */
    /* Some board doesn't work at high speed */
    ChangeFreq(16, 3, 1, 1); /*312Mhz*/   /* 16 * 13MHz = 208 Mhz Turbo-Mode */
    pcf50606_init();
    onkeyPressed = getINT1()&0x2;
    //printk("initail %x,%x\n",getOOCS(),onkeyPressed);
    PCFWatchDogEnable(0);
    //SerialInit(baud115k2);
    TimerInit();/* this should be done before net_init */
    Xs_LCD_Init();
    Display_Logo();

#if 1
    int key;
    wls_keypad_init();
    key=wls_keypad_getkey();
    if ( key != 0x54) {
        printk("Get key=%d\n", key);
        cli();
        #if 0
        if(key==32) {
            UsbDownloadImage();
        }
        else if (key == 46) {
            g_bWrite = 0;
            if (UsbDownloadImageEx()) {
                g_bWrite = 1;
                BootKernel(BOOT_ARG0, BOOT_ARG1);
            }
        }
        else if (key == 0x09) {
            printk("Wait a moment ...\n");
            if(FormatDocSafe()) {
                printk("Format Doc Fail!, Pls reboot and try again.\n");
                while(1);
            }
            else
                printk("Format DiskOnChip Successful!\n");

            UsbDownloadImageEx();
        }
        #else
        if (key == 46) {
            g_bWrite = 0;
            if (UsbDownloadImageEx()) {
                g_bWrite = 1;
                BootKernel(BOOT_ARG0, BOOT_ARG1);
            }
        }
        #endif
        sti();
    }

#if !defined(_RELEASE) || defined(_PRERELEASE)
    if (!SerialInputBlock_msec((char*)commandline,  1, 10)) {
        ArmSys();
    }
#endif
#endif
    unsigned long rts_ack_timeout = 5;
    for (i = 0; i < 3; i++) {
        rts_signal = 0xAA;
        rts_try = i;

        SerialOutputByte(rts_signal);
        retval = SerialInputBlock_msec(commandline, 1, rts_ack_timeout); /* 1 jiffie = 10 milli-sec */
        //printk("retval %d %x\n", retval, commandline[0]);
        //if( retval >= 1 )
        {
            if ((commandline[0] == 0xa4) || (commandline[0] == 0x62)) { /* 'b' */
                /* Jump to boot-loader command-mode */
                bAutoload = 0;
                verbose_level = 1;
                break;
            }
            else if ((commandline[0] == 0xa3) || (commandline[0] == 0x74)) {
                /* Jump to TAT command-mode */
                SerialOutputString("Jump to TAT mode");
                cli();
                tat_menu();
            }
            else {
                rts_ack_timeout += 10;
                bAutoload = 1;
                break;
            }
        }
    }

    if (bAutoload) {
        /* Jump to kernel */
        //SerialOutputString("\nAuto Boot Entered\n");
        if (!ReadImage(KERNEL_RAM_START)) {
            cli();
            BootKernel(BOOT_ARG0, BOOT_ARG1);
        }
    }

    onkeyPressed = 0;//reset
    ShowVersion();
    printk("Type \"help\" to get a list of commands\n");

    /* the command loop. endless, of course */
    for (;;) {
        DisplayPrompt("\nEldr>");

        retval = GetCommand(commandline, 128, 3600);
        if (retval > 0) {
            ExecuteCommand(commandline); /* parse and execute the input */
        }
        else if (retval == 0 && (commandline[0] == '\n' || commandline[0] == '\r')) {
            SerialOutputByte('\n');
        }
    }
}

void ShowVersion()
{
    printk( "\n\tElastos2.1 Bootloader\n\tVersion:%s, Time Stamp:%s\n", BOOTLOADVERSION, COMPILE_TIME_STAMP );
}

/*
  Parse and execute a command line
*/
void ExecuteCommand(u8* commandline)
{
    printk("ExecuteCommand>>>>> %s\n", commandline);

    int ReadLocation=0;
    int NextReadLocation=0;
    u32 ReadValue[3];
    int ParseResult[3];
    u8 FileName[128];

    if (MyStrCmp(commandline, "elastos", 7)) {
        ReadLocation = 7;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if ((ParseResult[0] != 1) || (ParseResult[1] != 1)) {
            ReadValue[0] = BOOT_ARG0;
            ReadValue[1] = BOOT_ARG1;
        }
        cli();
        ReadImage(KERNEL_RAM_START);
        printk("begin boot kernel!\n");
        BootKernel(ReadValue[0], ReadValue[1]);
    }
    else if (MyStrCmp(commandline, "identifydoc", 11)) {
        IdentifyDoc();
    }
    else if (MyStrCmp(commandline, "safeformatdoc", 13)) {
        printk("begin to safe format doc!\n");
        int ret = FormatDocSafe();
        if (ret)
            printk("Format DiskOnChip Failed(%d)!\n", ret);
        else
            printk("Format DiskOnChip Successful!\n");
    }
    else if (MyStrCmp(commandline, "writeipl", 8)) {
        ReadLocation = 8;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) {
            if (WriteIPL(ReadValue[0]))
                printk("Write IPL Failed!\n");
            else
                printk("Write IPL Successful!\n");
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "readipl", 7)) {
        ReadLocation = 7;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) {
            if (ReadIPL(ReadValue[0]))
                printk("Read IPL Failed!\n");
            else
                printk("Read IPL Successful!\n");
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "writespl", 8)) {
        ReadLocation = 8;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) {
            if (WriteSPL(ReadValue[0]))
                printk("Write SPL Failed!\n");
            else
                printk("Write SPL Successful!\n");
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "udl", 3)) {
        int splAddr;
        int nSize;
        printk("Download loader by Xmodem:");
        nSize = XModemReceive(( char *)(RAM_START + UDL_RAM_OFFSET));
        if (nSize != -1) {
            if ((splAddr = SplitRam((RAM_START + UDL_RAM_OFFSET), nSize)) != 0) {
                if (WriteSPL(splAddr)) {
                    printk("Write SPL Failed!\n");
                    return;
                }
                else {
                    printk("Write SPL Successful!\n");
                    if (WriteIPL(RAM_START + UDL_RAM_OFFSET)) {
                        printk("Write IPL Failed!\n");
                        return;
                    }
                    else
                        printk("Write IPL Successful!\n");
                }
            }
            else
                printk("Update Loader Failed\n");
        }
        else
            printk("Download Loader Failed");
    }
    else if (MyStrCmp(commandline, "readspl", 7)) {
        ReadLocation = 7;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) {
            if (ReadSPL(ReadValue[0]))
                printk("Read SPL Failed!\n");
            else
                printk("Read SPL Successful!\n");
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "writeimage", 10)) {
        int ret = WriteImage(KERNEL_RAM_START);
        if (ret)
            printk("Write Kernel Failed:%d\n", ret);
        else
            printk("Write Kernel Successful!\n");
    }
    else if (MyStrCmp(commandline, "readimage", 9)) {
        int ret = ReadImage(KERNEL_RAM_START);
        if (ret)
            printk("Load Kernel Failed:%d\n", ret);
        else
            printk("Load Kernel Successful!\n");
    }
    else if (MyStrCmp(commandline, "docinfo", 7)) {
        doc_info();
    }
    else if (MyStrCmp(commandline, "usbdn", 5)) {
        UsbDownloadImage();
    }
    else if (MyStrCmp(commandline, "keytest", 7)) {
        keyTest();
    }
    else if(MyStrCmp(commandline, "rboot", 5)) {
        ReadLocation = 5;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if((ParseResult[0]==1)&&(ParseResult[1]==1)){
            ReadBoot((int)(ReadValue[0]), ReadValue[1]);
        } else printk("Error : Some arguments are missing.\n");
    }
    else if(MyStrCmp(commandline, "wboot", 5)) {
        ReadLocation = 5;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if((ParseResult[0]==1)&&(ParseResult[1]==1)){
            WriteBoot((int)(ReadValue[0]), ReadValue[1]);
        } else printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "dump", 4)) {
        ReadLocation = 4;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1)) {
            DumpMem((u32*)(ReadValue[0]), ReadValue[1]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "help", 4)) {
        ReadLocation = 4;
        PrintHelp();
    }
    else if(MyStrCmp(commandline, "linux", 5)) {
        ReadLocation = 5;
        BootLinux();
    }
    else if (MyStrCmp(commandline, "jump", 4)) {
        ReadLocation = 4;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if ((ParseResult[0] == 1)) {
            printk("Code will jump to ");
            DebugOutputHex(ReadValue[0]);
            cli();
            Jump((u32*)(ReadValue[0]));
            sti();
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "memcpy", 6)) {
        ReadLocation = 6;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        ReadLocation+=NextReadLocation;
        ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1) && (ParseResult[2] == 1)) {
            MyMemCpyChar((u8*)(ReadValue[0]), (u8*)(ReadValue[1]), ReadValue[2]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "memcmp", 6)) {
        ReadLocation = 6;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        ReadLocation+=NextReadLocation;
        ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1) && (ParseResult[2] == 1)) {
            CmpMem((ReadValue[0]), (ReadValue[1]), ReadValue[2]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "memset ", 7)) {
        ReadLocation = 7;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        ReadLocation+=NextReadLocation;
        ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1) && (ParseResult[2] == 1)) {
            MyMemSetChar((u8*)(ReadValue[0]), (u8)(ReadValue[1]), ReadValue[2]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "memsetw", 7)) {
        ReadLocation = 7;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        ReadLocation+=NextReadLocation;
        ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[2]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1) && (ParseResult[2] == 1)) {
            MyMemSet((u32*)(ReadValue[0]), (u32)(ReadValue[1]), ReadValue[2]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "ram_test", 8)) {
        ReadLocation = 8;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1)) {
            ram_test((u32*)(ReadValue[0]), ReadValue[1]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "reset", 5)) {
        ReadLocation = 5;
        hw_reset();
    }
    else if (MyStrCmp(commandline, "ldr", 3)) {
        ReadLocation = 3;
        ParseResult[0]=ParseFileName(commandline+ReadLocation, &NextReadLocation, FileName);
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1)) {
            load_memory(FileName, (u32)ReadValue[0]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "str", 3)) {
        ReadLocation = 3;
        ParseResult[0]=ParseFileName(commandline+ReadLocation, &NextReadLocation, FileName);
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[2]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1) && (ParseResult[2] == 1)) {
            store_memory(FileName, (u32)ReadValue[0], (u32)ReadValue[1]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "xdn ", 4)) {
        ReadLocation = 4;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) {
            XModemReceive((u8*)(ReadValue[0]));
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "xup ", 4)) {
        ReadLocation = 4;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1)) {
            xmodemTransmit((u8*)ReadValue[0], ReadValue[1]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    } /*else if(MyStrCmp(commandline, "udn ", 4)) {
        ReadLocation = 4;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if((ParseResult[0]==1)&&(ParseResult[1]==1)){
            udownload_cmd((u32 *)ReadValue[0], ReadValue[1]);
        } else printk("Error : Some arguments are missing.\n");
    }*/
    else if (MyStrCmp(commandline, "pmu_dump", 8)) {

        pcf50606_dump_registers();
    }
    else if (MyStrCmp(commandline, "pmu_set", 7)) {
        /* usage: pmu_set <power_name> <voltage_value> */
        /*          - ex) pmu_set D1REG 11 */
        ReadLocation = 7;
        ParseResult[0]=ParseFileName(commandline+ReadLocation, &NextReadLocation, FileName);
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1)) {
            //load_memory(FileName, (u32)ReadValue[0]);
            pcf50606_pmu_set_voltage( FileName, ReadValue[0] );
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "md5sum", 6)) {
        ReadLocation = 6;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if ((ParseResult[0] == 1) && (ParseResult[1] == 1)) {
            md5_stream((char*)&ReadValue[0], ReadValue[1]);
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "verbose", 7)) {
        ReadLocation = 7;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) { /* input ok, now run the script */
            if (ReadValue[0] >= 1)
                verbose_level = 2;
            else
                verbose_level = 0;
        }
        else
            SerialOutputString("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "halt", 4)) {
        ReadLocation = 4;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0] == 1) { /* input ok, now run the script */
            msleep(ReadValue[0]);   /* in ms */
        }
        else
            SerialOutputString("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "status", 6)) {
        ReadLocation = 6;
        printk("jiffies       : %d\n", jiffies);
        printk("jiffies_div10 : %d\n", jiffies_div10);
        ShowUsbPinState();
    }
    else if (MyStrCmp(commandline, "version", 7)) {
        ShowVersion();
    }
    else if (MyStrCmp(commandline, "bcm_on2pc", 9)) {
        bcm2121_on2pc();
    }
    else if (MyStrCmp(commandline, "bcm_download2pc", 15)) {
        bcm2121_download2pc();
    }
    else if (MyStrCmp(commandline, "bcm_active", 10)) {
        bcm2121_active();
    }
    else if (MyStrCmp(commandline, "bcm_inactive", 12)) {
        bcm2121_inactive();
    }
    else if (MyStrCmp(commandline, "wlogo", 5)) {
        ReadLocation = 5;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if (ParseResult[0] && ParseResult[1]) {
            ReadLocation = WriteLogo(ReadValue[0], ReadValue[1]);
            if (ReadLocation)
                printk("Write logo error:%d\n", ReadLocation);
            else
                printk("Write logo successful\n");
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "rlogo", 5)) {
        ReadLocation = 5;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        ReadLocation+=NextReadLocation;
        ParseResult[1]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[1]));
        if (ParseResult[0] && ParseResult[1]) {
            ReadLocation = ReadLogo(ReadValue[0], ReadValue[1]);
            if (ReadLocation)
                printk("Read logo error:%d\n", ReadLocation);
            else
                printk("Read logo successful\n");
        }
        else
            printk("Error : Some arguments are missing.\n");
    }
    else if (MyStrCmp(commandline, "wtatt", 5)) {
        ReadLocation = 5;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0]) {
            ReadLocation = WriteTatTable((unsigned char *)ReadValue[0]);
            if (ReadLocation)
                printk("Write tatt error:%d\n", ReadLocation);
            else
                printk("Write tatt successful\n");
        }
        else
            printk("Error : Some arguments error.\n");
    }
    else if (MyStrCmp(commandline, "rtatt", 5)) {
        ReadLocation = 5;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if (ParseResult[0]) {
            ReadLocation = ReadTatTable((unsigned char *)ReadValue[0]);
            if (ReadLocation)
                printk("Read tatt error:%d\n", ReadLocation);
            else
                printk("Read tatt successful\n");
        }
        else
            printk("Error : Some arguments error.\n");
    }
    else if (MyStrCmp(commandline, "u", 2) || MyStrCmp(commandline, "u ", 2)) {
        unsigned long uImageBase = KERNEL_RAM_START;

        ReadLocation = 2;
        ParseResult[0]=ParseNumber(commandline+ReadLocation, &NextReadLocation, &(ReadValue[0]));
        if(ParseResult[0]==1 && ReadValue[0]) {
            uImageBase = ReadValue[0];
            printk("uImageBase = 0x%08x\n", uImageBase);
            _UsbDownloadImageEx(uImageBase);
        }
        else {
            g_bWrite = 0;
            if (UsbDownloadImageEx()) {
                g_bWrite = 1;
                BootKernel(BOOT_ARG0, BOOT_ARG1);
            }
        }
    }
    else {
        printk("*** Unknown command:  %s \n", commandline);
        PrintHelp();
    }
}

/*
  Jump to the pre-copied kernel in the RAM
*/
typedef struct BootInfo {
    unsigned int LoadAddress;
    unsigned int ImageBase;
    unsigned int ImageSize;
    unsigned int MemorySize;
    unsigned int WriteMagic;
    unsigned int Reserved1;
    unsigned int Reserved2;
    unsigned int Reserved3;
} BootInfo;

typedef struct PackageInfo {
    unsigned int    uReserved;
    void            *modules;
    unsigned int    uNumberOfModules;
    unsigned int    uPackageSize;
    char            *szCommandLine;
} PackageInfo;

void BootKernel(int arg0, int arg1)
{
    BootInfo *pLoadInfo = (BootInfo *)RAM_START;
    int *pEntry;
    void (*theKernel)(int zero, int arch);
    // find kernel entry
    pEntry = (int*)(KERNEL_RAM_START + 0x3c);

    if ((*(int *)(*pEntry + KERNEL_RAM_START)) != 0x00004550) {
        printk("Kernel is not PE format!\n");
        return;
    }
    pEntry = (int*)(KERNEL_RAM_START + (*pEntry) + 0x28);
    theKernel = (void*)((*pEntry) + KERNEL_RAM_START);

    //Prepare for jump kernel
    DisableProtectKey();
    jiffies = 1000;
    check_onkey();

    // set kernel arguments
    if (!arg1) {
        arg1 = (int)pLoadInfo;
        pLoadInfo->WriteMagic = 0;
        pLoadInfo->MemorySize = 0x4000000;
        pLoadInfo->LoadAddress = KERNEL_RAM_START;
        pLoadInfo->ImageBase = 0xc0020000;
        pEntry = (int*)(KERNEL_RAM_START + 0x8);
        pLoadInfo->ImageSize = ((PackageInfo *)(*pEntry + KERNEL_RAM_START))\
                             ->uPackageSize;
    }
/*  printk("loadinfo(%08x):WriteMagic%08x\n"
           "MemorySize%08x\n"
           "LoadAddress%08x\n"
           "ImageBase%08x\n"
           "ImageSize%08x\n",
        pLoadInfo,
        pLoadInfo->WriteMagic,
        pLoadInfo->MemorySize,
        pLoadInfo->LoadAddress,
        pLoadInfo->ImageBase,
        pLoadInfo->ImageSize);
*/
    printk("jump to kernel\n");
    cli();
    theKernel(arg0,arg1);
    sti();

    printk("Hey, the kernel returned! This should not happen.\r");
}

void BootLinux()
{
	void (*theKernel)(int zero, int arch) = (void (*)(int, int))0xa0008000;

	theKernel(0, 406);

	printk("Hey, the kernel returned! This should not happen.\r");
}

void Jump(u32* address)
{
    void (*Func)(void)= (void(*)(void))address;

    (*Func)();

    /* To return to this point, code should save every registes used,
     * lr, etc. and return to the lr and should never modify the SP
     */
}

static void WatchdogReset()
{
    __REG(OST_BASE_PHYSICAL+OWER_OFFSET) = 1;
    __REG(OST_BASE_PHYSICAL+OSMR3_OFFSET) =
        __REG(OST_BASE_PHYSICAL+OSCR0_OFFSET) + 0x200;

    printk("Can not reset.Please power off\n");
    while (TRUE) {
    }
}

void hw_reset(void)
{
    int start_time;
    start_time = TimerGetTime();

    printk("Auto reset...\n");
    while((TimerGetTime()-start_time) < 2);
    WatchdogReset();
}

int SplitRam(int addr, int nSize)
{
    int desAddr = addr + 0x100000;
    int ret = desAddr;
    int noCpy;
    int i;
    long len = *((long *)(addr + 0x7fc));
    long magic = *((long *)(addr + 0x7f0));

    if (nSize <= 0) {
        printk("no boot loader data\n");
        return 0;
    }
    else if (nSize > 0x80000) {
        printk("too large size\n");
        return 0;
    }
    else if (nSize < len || len < 0 || len > BDK0_LENGTH
        || magic != ELDR_MAGIC) {
        printk("data error\n");
        return 0;
    }

    noCpy = (len + 0x1ff) >> 9;
    noCpy = noCpy > 0x400? 0x400: noCpy;

    for (i = 0; i < noCpy; i++) {
        memcpy((void*)desAddr, (void*)addr, 0x200);
        desAddr += 0x200;
        memcpy((void*)desAddr, (void*)addr, 0x200);
        desAddr += 0x200;
        addr += 0x200;
    }

    return ret;
}

void ArmSys()
{
    unsigned long packsize,flashoffset;
    unsigned long buffer = KERNEL_RAM_START;
    long IsWriteFlash;

//    SerialOutputRawByte('0');
//    SerialOutputRawByte('1');
//    SerialOutputRawByte('2');
//    SerialOutputRawByte('3');

    // Send query signal,ask for file length
    SerialOutputRawByte('?');

    //  Get file length nowait
    flashoffset = SerialInputDWordWithTimeout();
    packsize = SerialInputDWordWithTimeout();
    IsWriteFlash = packsize & 0x80000000;
    packsize = packsize & ~0x80000000;

    if (packsize) {    // get image from armsys

        // end ready signal
        SerialOutputRawByte('<');

        // receive the file data
        SerialInputBlock_msec((char*)buffer, packsize, 20*60*1000/*20 minutes*/);

        SerialOutputRawByte('>');

        // jump to run program if u don't need write flash
        if (IsWriteFlash) {
            printk("Write Kernel to DOC\n");
            if (WriteImage(buffer))
                printk("Write Kernel Failed!\n");
            else
                printk("Write Kernel Succeeded\n!\n");
        }

        // image is already in the dram
        BootKernel(0, 0);
    }
}

void PrintHelp(void)
{
    printk("\nHelp for Elastos2.1 Bootloader:\n\n");
    printk("* elastos [arg0 arg1]  Boot Elastos2.1 with optional kernel options\n");
    printk("* udl                  Update bootloader by xmodem\n");
    printk("* usbdn                Download kernel image to RAM by USB\n");
    printk("                       and write to kernel partition on DOC\n" );
    printk("* u                    Download kernel image to RAM by USB and\n");
    printk("                       run into kernel\n" );
    printk("* reset                cpu reset\n" );
    printk("* xdn {add}            Download a file via xMODEM to the address of {add}\n");
    printk("* docinfo              Infomation of DiskOnChip\n");
    printk("* safeformatdoc        Format DOC. NOTE: Safe update loader after formatdoc\n");
    printk("* writeimage           Write  Elastos.img\n");
    printk("* readimage            Read   Elastos.img\n");
    printk("* rboot {addr} {len}   Read the contents of BDK0\n");
    printk("* wboot {addr} {len}   Write the contents of BDK0\n");
    printk("* dump {add} {len}     Dump the contents of the memory\n");
    printk("* jump {add}           Brach to the given {add}\n");
    printk("* memset {add} {val} {len}\n");
    printk("                       Set the memory with given {val}\n");
    printk("* memcpy {dest_add} {source_add} {len}\n");
    printk("                       Copy memory from the source to the destination\n");
    printk("* memcmp {add1} {add2} {len}\n");
    printk("                       Compare contents of memory\n");
    printk("* ldr [-l : -h : -b] {add}\n");
    printk("                       Display [32:16:8]bits memory contents.\n");
    printk("* str [-l : -h : -b] {add} {val}\n");
    printk("                       Store [32:16:8]bits {val} on {add}\n");
    printk("* pmu_dump [reg_name]  Dump the contents of each pmu related register\n");
    printk("                       of pcf50606 chip.\n" );
    printk("* pmu_set <power_name> <voltage>\n");
    printk("                       power_name:<D1REG|D2REG|D3REG|DCD|DCDE|DCUD|IOREG|LPREG>\n" );
    printk("                       voltage: 9 ~ 55\n" );
    printk("* bcm_on2pc            Power on BCM2121 and switch UART to PC\n");
    printk("* bcm_download2pc      Set BCM2121 to download mode and switch UART to PC\n");
    printk("* bcm_active           Wake BCM2121\n");
    printk("* bcm_inactive         Put BCM2121 into sleep mode\n");
    printk("* wlogo {addr} {len}   Write logo to DOC (len blow 0x30000 bytes)\n");
    printk("* rlogo {addr} {len}   Read logo from DOC (len blow 0x30000 bytes)\n");
    printk("* wtatt {addr} {len}   Write TAT table to DOC (len blow 0x40000 bytes)\n");
    printk("* rtatt {addr} {len}   Read TAT table from DOC (len blow 0x40000 bytes)\n");
    printk("* help                 Show this messages\n");
}
